package cxy.highConcurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 首先我们创建了一个线程池 executor 、一个 CompletionService 对象 cs 和一个Future<Integer>类型的列表 futures，
 * 每次通过调用 CompletionService 的 submit() 方法提交一个异步任务，会返回一个 Future 对象，
 * 我们把这些 Future 对象保存在列表 futures 中。通过调用 cs.take().get()，我们能够拿到最快返回的任务执行结果，
 * 只要我们拿到一个正确返回的结果，就可以取消所有任务并且返回最终结果了。
 * @author admin
 *
 */
public class CompletionServiceDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {

		// 创建线程池
		ExecutorService executor = Executors.newFixedThreadPool(3);
		// 创建CompletionService
		CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
		// 用于保存Future对象
		List<Future<Integer>> futures = new ArrayList<>(3);
		// 提交异步任务，并保存future到futures
		futures.add(cs.submit(() -> geocoderByS1()));
		futures.add(cs.submit(() -> geocoderByS2()));
		futures.add(cs.submit(() -> geocoderByS3()));
		// 获取最快返回的任务执行结果
		Integer r = 0;
		try {
			// 只要有一个成功返回，则break
			for (int i = 0; i < 3; ++i) {
				r = cs.take().get();
				// 简单地通过判空来检查是否成功返回
				if (r != null) {
					break;
				}
			}
		} finally {
			// 取消所有任务
			for (Future<Integer> f : futures)
				f.cancel(true);
		}
		// 返回结果
		System.out.println("result:" + r);
		executor.shutdown();
		return;
	}
	
	static int geocoderByS1() {
		System.out.println("geocoderByS1");
		sleep(1, TimeUnit.SECONDS);
		return 1;
	}
	
	static int geocoderByS2() {
		System.out.println("geocoderByS2");
		sleep(2, TimeUnit.SECONDS);
		return 2;
	}
	
	static int geocoderByS3() {
		System.out.println("geocoderByS3");
		sleep(2, TimeUnit.SECONDS);
		return 3;
	}
	
	static void sleep(int t, TimeUnit u) {
		try {
			u.sleep(t);
		} catch (InterruptedException e) {
		}
	}
}
